package com.caikun.gateway.filter;

import com.caikun.model.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * JWT认证过滤器 - 用于网关层的请求鉴权，验证Token并添加用户信息到请求头，已完成
 */
@Slf4j
@Component
public class JwtAuthGatewayFilterFactory extends AbstractGatewayFilterFactory<JwtAuthGatewayFilterFactory.Config> {

    public JwtAuthGatewayFilterFactory() {
        super(Config.class);
    }

    /**
     * 核心过滤逻辑实现
     * @param config 过滤器配置
     * @return 网关过滤器实例
     */
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();

            log.info("请求路径：{}", request.getURI().getPath());

            // 1. 检查是否需要跳过验证（白名单路径）
            if (isSkipAuth(request)) {
                return chain.filter(exchange);
            }

            // 2. 获取并验证Token
            String token = extractToken(request);
            log.info("token: " + token);

            if (token == null) {
                return onAuthFailure(exchange, "Missing authorization token" + token, HttpStatus.UNAUTHORIZED);
            }

            if (!JwtUtils.isTokenExpired(token)) {
                return onAuthFailure(exchange, "Invalid or expired token", HttpStatus.UNAUTHORIZED);
            }

            // 3. 解析Token并将用户信息添加到请求头（下游服务使用）
            Claims claims = JwtUtils.parseToken(token);
            ServerHttpRequest modifiedRequest = addUserHeaders(request, claims);

            // 4. 继续过滤器链处理
            return chain.filter(exchange.mutate().request(modifiedRequest).build());
        };
    }

    /**
     * 判断请求路径是否需要跳过认证
     * @param request HTTP请求对象
     * @return true表示跳过认证，false需要认证
     */
    private boolean isSkipAuth(ServerHttpRequest request) {
        String path = request.getURI().getPath();
        // 配置不需要认证的路径（通常包括登录、公开API、健康检查等）
        return path.startsWith("/user/login") ||
                path.equals("/user/login/") ||
                path.startsWith("/user/register") ||
                path.equals("/user/register/") ||
                path.equals("/place/place-type") ||               // 车位类型查询
                path.matches("/place/place-type/[^/]+")   // 车位信息查询
                || true;
    }

    /**
     * 从请求头中提取JWT令牌
     * @param request HTTP请求对象
     * @return 提取到的令牌（无Bearer前缀），未找到返回null
     */
    private String extractToken(ServerHttpRequest request) {
        String authHeader = request.getHeaders().getFirst(JwtUtils.Header);

        return authHeader;
    }

    /**
     * 认证失败时的响应处理
     * @param exchange 请求响应交换对象
     * @param error 错误信息
     * @param status HTTP状态码
     * @return 包含错误响应的Mono对象
     */
    private Mono<Void> onAuthFailure(ServerWebExchange exchange, String error, HttpStatus status) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(status);
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/json");

        // 构造JSON格式的错误响应
        String body = String.format("{\"code\": %d, \"message\": \"%s\"}",
                status.value(), error);

        return response.writeWith(Mono.just(response.bufferFactory().wrap(body.getBytes())));
    }

    /**
     * 将用户信息添加到请求头（供下游服务使用）
     * @param request 原始请求
     * @param claims JWT声明信息
     * @return 修改后的请求对象
     */
    private ServerHttpRequest addUserHeaders(ServerHttpRequest request, Claims claims) {
        return request.mutate()
                .header("X-User-Id", claims.getSubject()) // 用户ID
                .header("X-User-Roles", String.join(",", claims.get("roles", List.class))) // 用户角色
                .build();
    }

    /**
     * 过滤器配置类（可扩展配置参数）
     */
    public static class Config {
        public Config() {
        }
        // 可扩展参数
    }
}
